package info.liujiachen.test.spring.security.util;

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTCreator;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.auth0.jwt.interfaces.Verification;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.crypto.codec.Base64;
import org.springframework.security.crypto.encrypt.Encryptors;
import org.springframework.stereotype.Component;
import org.springframework.util.DigestUtils;

import java.util.Calendar;
import java.util.Date;
import java.util.UUID;

@Component
public class JwtUtil {

    // 日志
    private static Logger LOGGER = LoggerFactory.getLogger(JwtUtil.class);

    private final static String secretKey = "5S1WQVMKCHt8w4LydcWl4CGFYoH2tgtmMDzd955KySY=";
    private static String issuer;
    private static String subject;
    public static int validity;
    private static int refresh;
    private static String salt;

    @Value("${app.jwt.issuer}")
    public void setIssuer(String issuer) {
        JwtUtil.issuer = issuer;
    }

    @Value("${app.jwt.subject}")
    public void setSubject(String subject) {
        JwtUtil.subject = subject;
    }

    @Value("${app.jwt.validity}")
    public void setValidity(Integer validity) {
        JwtUtil.validity = validity;
    }

    @Value("${app.jwt.refresh}")
    public void setRefresh(Integer refresh) {
        JwtUtil.refresh = refresh;
    }

    @Value("${app.salt}")
    public void setSalt(String salt) {
        JwtUtil.salt = salt;
    }

    public static String create(String username, String password) {
        JWTCreator.Builder jwt = JWT.create();
        //
        jwt.withIssuer(md5(JwtUtil.issuer));
        jwt.withSubject(md5(JwtUtil.subject));
        jwt.withJWTId(md5(UUID.randomUUID().toString()));
        //
        Calendar calendar = Calendar.getInstance();
        jwt.withIssuedAt(calendar.getTime());
        calendar.add(Calendar.MILLISECOND, JwtUtil.validity);
        jwt.withExpiresAt(calendar.getTime());
        //
//        jwt.withAudience(encrypt(password), encrypt(username));
        jwt.withAudience(password, username);
        //
        return jwt.sign(Algorithm.HMAC256(JwtUtil.salt));
    }

    public static String refresh(String token) {
        //
        DecodedJWT jwt = JWT.decode(token);
        long refreshIssuedAt = jwt.getIssuedAt().getTime() + JwtUtil.refresh;
        long now = new Date().getTime();
        if (refreshIssuedAt <= now) {
//            String username = decrypt(jwt.getAudience().get(0));
//            String password = decrypt(jwt.getAudience().get(1));
            String username = jwt.getAudience().get(0);
            String password = jwt.getAudience().get(1);
            token = create(username, password);
        }
        return token;
    }

    public static void verify(String token) {
        //
        DecodedJWT jwt = JWT.decode(token);
        //
        Verification verification = JWT.require(Algorithm.HMAC256(JwtUtil.salt));
        //
        verification.withIssuer(md5(JwtUtil.issuer));
        verification.withSubject(md5(JwtUtil.subject));
        verification.withJWTId(jwt.getId());
        //
        verification.withAudience(jwt.getAudience().get(0), jwt.getAudience().get(1));
        //
        JWTVerifier verify = verification.build();
        try {
            verify.verify(token);
        } catch (Exception e) {
            LOGGER.error("TOKEN验证错误", e);
            throw new BadCredentialsException("Token Verify Error");
        }
    }

    public static String getUsername(String token) {
        DecodedJWT jwt = JWT.decode(token);
//        return decrypt(jwt.getAudience().get(0));
        return jwt.getAudience().get(1);
    }

    public static String getPassword(String token) {
        DecodedJWT jwt = JWT.decode(token);
//        return decrypt(jwt.getAudience().get(1));
        return jwt.getAudience().get(0);
    }

    public static String md5(String value) {
        return DigestUtils.md5DigestAsHex((value + JwtUtil.salt).getBytes());
    }

    /**
     * 加密
     *
     * @param plainString 明文
     * @return
     */
    public static String encrypt(String plainString) {
        // 明文
        byte[] byteArray = plainString.getBytes();

        // 加密，设置密钥和随机数
        byte[] cipherArrayTemp = Encryptors.standard(secretKey, JwtUtil.salt).encrypt(byteArray);
        byte[] cipherArray = Base64.encode(cipherArrayTemp);
        return new String(cipherArray);
    }

    /**
     * 解密
     *
     * @param cipherString 密文
     * @return
     */
    public static String decrypt(String cipherString) {
        // 密文
        byte[] byteArray = cipherString.getBytes();
        byte[] plainArrayTemp = Base64.decode(byteArray);
        // 解密
        byte[] plainArray = Encryptors.standard(secretKey, JwtUtil.salt).decrypt(plainArrayTemp);
        return new String(plainArray);
    }

}
